/*****************************************************************************
* File Name: keyboard.c
*
* Version: 1.0
*
* Description:
* This file contains API for reading the button status present in matrix format
*
* Note:
* Define DISABLE_KEYBOARD in platform.h to disable keyboard module
* Define KEYBOARD_MULTIMEDIA_SUPPORT in platform.h to enable multimedia support in keyboard module
* Define ENABLE_IR_CODES in platform.h to enable IR support in keyboard module
* 
* Owner: MRAO
*
* Related Document:
* cy_pin module data sheet
*
* Hardware Dependency:
* Keypad having 3x3 Matrix.
*
* Code Tested With:
* 1. PSoC Creator 3.1 
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/
#include "keyboard.h"
#include "ble.h"
#include "device.h"

#ifndef DISABLE_KEYBOARD

#define KEYBOARD_REPORT_SIZE                            8

extern const Key keyboard_ScanTable[COLUMNS * ROWS];		/* Keyboard key array */ 
extern const uint16 multimedia_Keyboard_ScanTable[]; 		/* Multimedia key array */
extern const uint8 keyboard_Other_ScanTable[]; 			/* Other key array */
extern const uint8 keyboard_Ir_ScanTable[];                     /* Keyboard IR Key values array */

bool isButtonStatusChanged;
bool isPairButtonPressed = false; /*Variable to check pair button status*/
bool isPairButtonDown = false; /*Variable to check pair button status*/
bool isButtonPressed = false;


#ifdef BACK_CHANNEL_SUPPORT
static uint8 backChannelRequest = 0;                            /* Is there any back channel request present */
static uint8 prevScanCode = 0;                                  /* Previous scan key code */
#endif /* BACK_CHANNEL_SUPPORT */

static KeyElement keyQueue[KEY_QUEUE_LEN];                      /* Queue containing key pressed */
static uint32 lastTransferTimeStamp = 0;                        /* Time stamp */
static uint8 prevReportType = 0;                                /* To store previos report type */
static bool sendKeepAlivePacket = false;
static bool prevSendKeepAlivePacket = false;

#if (NO_COLUMN_PORTS > 1) 
static uint8 prevColumnStatus[ROWS][NO_COLUMN_PORTS],curColumnStatus[ROWS][NO_COLUMN_PORTS];
#else
static uint8 prevColumnStatus[ROWS],curColumnStatus[ROWS];      /* Variables to store previous and current column status values */
#endif /* (NO_COLUMN_PORTS > 1) */

static uint8 prevCol = 0;                                       /* Previous column value */
static bool sendKeyboardReport = false;
static ReportType isUpKeyDetected = NO_REPORT;
static uint8 prevClickStatus = 0;
static uint8 keyPressedNum;

static void Keyboard_Detect_Keys(void);                         /* Detect which key pressed or released */
static void Keyboard_Remove_Queue(uint8 queue_index);           /* Remove un-pressed key entry from the Queue */

extern uint8 MotionSensorState;
/*****************************************************************************
* Function Name: Keyboard_Interrupt_Callbck()
******************************************************************************
* Summary:
* This functions is a callback function for keypad interrupts
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Calls the Device Activity detected API for indicating the framework that user activity 
* is detected
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Interrupt_Callbck(void)
{
    Keyboard_Columns_ClearInterrupt();
    DEVICE_ACTIVITY_DETECTED();
}

/*****************************************************************************
* Function Name: Keyboard_Add_Queue()
******************************************************************************
* Summary:
* Adds the index to the queue
*
* Parameters:
* index - to be added into the queue
*
* Return:
* None
*
* Theory:
* Find free position in the KeyQueue, add current key values in free position 
*
* Side Effects:
* keyQueue is updated
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Add_Queue(uint8 index)
{
    uint8 i,freePosition = INVALID;
    KeyType keyType = keyboard_ScanTable[index].keyType;
    uint8 scanCode = keyboard_ScanTable[index].scanCode; 
    KeyElement key;
    /* If no key is detected then return */
    if(keyType == NO_KEY_TYPE)
    {
        return;
    }
#ifndef KEYBOARD_MULTIMEDIA_SUPPORT
    else if(keyType == MULT_KEY || 
            keyType == PWR_KEY)
    {
        Debug_Print(DEBUG_MESSAGE_LEVEL_3, "No Multimedia keys \r\n");
        return;
    }
#endif /* KEYBOARD_MULTIMEDIA_SUPPORT */
    /* If scan code is NOKEY and key type is not a Multimedia key, then return */
    if(scanCode == NOKEY && (keyType != MULT_KEY))
    {
        return;
    }
    /* Check for the free position in queue to add new entry */
    for (i = 0; i < KEY_QUEUE_LEN; ++i)
    {
        key = keyQueue[i];
        if((key.index == INVALID_INDEX) && (freePosition == INVALID))
        {
            freePosition = i;
        }
        else if(key.index == index)
        {
            keyQueue[i].keyState = KEY_STATE_DOWN;
            return;
        }
    }
    /* Add new key entry to the queue */
    if(freePosition != INVALID)
    {
        keyQueue[freePosition].keyState = KEY_STATE_DOWN;
        keyQueue[freePosition].index = index;
        keyQueue[freePosition].debounceValue = KEYBOARD_DEBOUNCE_COUNT;
        keyQueue[freePosition].isDataSent = 0;     
    }
    return;
}

/*****************************************************************************
* Function Name: Keyboard_Update_Queue()
******************************************************************************
* Summary:
* Update the debounce values in the queue 
*
* Parameters:
* None
*
* Return:
* bool - true if any data need to be reported
*
* Theory:
* Decrements the debounce value and reports if the debounce value has reached zero
*
* Side Effects:
* keyQueue is updated
* 
* Note:
* None
*****************************************************************************/
static bool Keyboard_Update_Queue(void)
{
    bool sendReport = false,keyPressed=false;
    uint8 i;
    KeyElement key;
		// add zozo
		uint8 keysPairCnt=0;
		keyPressedNum =0;
    /*Update queue entries by checking status of keys*/
    for (i = 0; i < KEY_QUEUE_LEN; ++i)
    {
        key = keyQueue[i];
        if(key.index != INVALID_INDEX)
        {
            if(key.debounceValue == 0)
            {
                if(key.isDataSent == 0 || isUpKeyDetected)
                {
                    sendReport = true;
                }
                
                if(key.keyState == KEY_STATE_DOWN)
                {                    
                    keyPressed = true;
										// key sequences add zozo
										keyPressedNum++;
										if(key.index == MENU_INDEX)
											{
												keysPairCnt++;
											}
										else if(key.index == RETURN_INDEX)
											{
												keysPairCnt++;
											}
										Debug_Print(DEBUG_MESSAGE_LEVEL_3, "num=%d,index=%d\r\n",keyPressedNum,key.index);

                }
                if(key.isDataSent == 1)
                {
                    Keyboard_Remove_Queue(i);
                }
            }
            else
            {
                keyQueue[i].debounceValue--;
            }
        }
    }
    sendKeepAlivePacket = keyPressed | prevSendKeepAlivePacket;
    prevSendKeepAlivePacket = keyPressed;
		
		//// key sequences add zozo
		if(keysPairCnt == KEYS_PAIR_CNT)
			{
				if(!isPairButtonPressed)
					{
						isPairButtonDown = true;
						Debug_Print(DEBUG_MESSAGE_LEVEL_4, "pair Button down\r\n");
					}
				else
					{
						isPairButtonDown = false;
					}
					

				isPairButtonPressed  = true;
				

			}
		else
			{
				isPairButtonPressed  = false;
				isPairButtonDown  = false;
			}
			
    return sendReport;
}

/*****************************************************************************
* Function Name: Keyboard_Remove_Queue()
******************************************************************************
* Summary:
* Removes the index from the queue
*
* Parameters:
* queue index - index that need to be removed
*
* Return:
* None
*
* Theory:
* Index of KeyQueue will be set as INVALID_INDEX, which is considered as free 
* position.
*
* Side Effects:
* 
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Remove_Queue(uint8 queue_index)
{
    /* If key state is UP then remove that key entry from queue */
    if(keyQueue[queue_index].keyState == KEY_STATE_UP)
    {
        Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Remove Queue = %d\r\n",queue_index);        
        keyQueue[queue_index].index = INVALID_INDEX;
    }
}

/*****************************************************************************
* Function Name: Keyboard_Init()
******************************************************************************
* Summary:
* Initialize the keyboard module 
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Initialize the keyboard interrupt and keyQueue as INVALID_INDEX   
*
* Side Effects:
* keyQueue is updated
* 
* Note:
* None
*****************************************************************************/
void Keyboard_Init(void)
{
    uint8 i;
    Keyboard_Columns_Interrupt_StartEx(Keyboard_Interrupt_Callbck);
    Keyboard_Columns_Interrupt_Disable();
    /* Initialize the Queue index with INVALID_INDEX to show queue is free initially */
    for (i = 0; i < KEY_QUEUE_LEN; i++)
    {
        keyQueue[i].index = INVALID_INDEX;
    }
		Debug_Print(DEBUG_MESSAGE_LEVEL_5,"KeyBoard_Init\r\n");
}

/*****************************************************************************
* Function Name: Keyboard_Scan_Column()
******************************************************************************
* Summary:
* Scans the columns by exciting one row at a time
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* To search in row by column matrix where keyboard button is pressed.
*
* Side Effects:
* Keyboard_Columns_Write is updated
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Scan_Column(void)
{
    uint8 rowMask = 1,row;
#if (NO_COLUMN_PORTS > 1)
    uint8 i;
#endif /* (NO_COLUMN_PORTS > 1) */

    bool isNewKeyPressed = false;
    Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Keyboard_Scan_Column API \r\n");
    /*Scan row by column for any key Activity*/
    for(row=0;row<ROWS;row++)
    {
        Keyboard_Rows_Write(((~(uint8)rowMask) & (Keyboard_Rows_MASK>>Keyboard_Rows_SHIFT)));
        KeyboardDelay();
        Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Row = %d\r\n", ((~(uint8)rowMask) & Keyboard_Rows_MASK));
#if (NO_COLUMN_PORTS > 1)
        curColumnStatus[row][0] = (~Keyboard_Columns_1_Read() & (Keyboard_Columns_1_MASK>>Keyboard_Columns_1_SHIFT));
        curColumnStatus[row][1] = (~Keyboard_Columns_2_Read() & (Keyboard_Columns_2_MASK>>Keyboard_Columns_2_SHIFT));
        curColumnStatus[row][2] = (~Keyboard_Columns_3_Read() & (Keyboard_Columns_3_MASK>>Keyboard_Columns_3_SHIFT));
        
        Debug_Print(DEBUG_MESSAGE_LEVEL_3, "lo_col = ",curColumnStatus[row][0]);
        Debug_Print(CYDEBUG_MESSAGE_LEVEL_3, "mid_col = ",curColumnStatus[row][1]);
        Debug_Print(CYDEBUG_MESSAGE_LEVEL_3, "hi_col = ",curColumnStatus[row][2]);
        
        Keyboard_Columns_1_Write(Keyboard_Columns_1_MASK>>Keyboard_Columns_1_SHIFT);
        Keyboard_Columns_2_Write(Keyboard_Columns_2_MASK>>Keyboard_Columns_2_SHIFT));
        Keyboard_Columns_3_Write(Keyboard_Columns_3_MASK>>Keyboard_Columns_3_SHIFT));
#else
        curColumnStatus[row] = (~Keyboard_Columns_Read() & (Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT));
        Debug_Print(DEBUG_MESSAGE_LEVEL_3, "lo_col = %x\r\n",curColumnStatus[row]);
        Keyboard_Columns_Write(Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT);
#endif /* (NO_COLUMN_PORTS > 1) */

        Keyboard_Rows_Write(Keyboard_Rows_MASK>>Keyboard_Rows_SHIFT);
#if (NO_COLUMN_PORTS > 1)
        for(i=0;i<NO_COLUMN_PORTS;i++)
        {
            if(curColumnStatus[row][i] ^ prevColumnStatus[row][i])
            {
                isNewKeyPressed = true;
            }
        }
#else
        /*Check for previos and current column status of row to get any key pressed*/
        if(curColumnStatus[row] ^ prevColumnStatus[row])
        {
            isNewKeyPressed = true;
        }
#endif /* (NO_COLUMN_PORTS > 1) */
        rowMask = rowMask<<BIT_1_POSITION;
    }
    /*If any new key is pressed then detect that key*/
    if(isNewKeyPressed)
    {
        isButtonStatusChanged = true;
        Keyboard_Detect_Keys();
    }
    else
    {
        isButtonStatusChanged = false;
    }
}

/*****************************************************************************
* Function Name: Keyboard_Update_Release_Key_State()
******************************************************************************
* Summary:
* Updates the key status for the key is released
*
* Parameters:
* index - release key index
*
* Return:
* None
*
* Theory:
* Recently released keyboard state will be updated.
*
* Side Effects:
* keyQueue and isUpKeyDetected is updated
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Update_Release_Key_State(uint8 index)
{
    uint8 i;
    KeyType keyType;
    uint8 scanCode;
    /*Update the released key state in Queue entry*/
    for (i = 0; i < KEY_QUEUE_LEN; ++i)
    {
        if(keyQueue[i].index == index)
        {
            Debug_Print(DEBUG_MESSAGE_LEVEL_3,"update release state index",index);
            if((index != INVALID_INDEX) && (keyQueue[i].debounceValue == 0))
            {
  						if(MotionSensorState && (index == 4 || index == 6))
  							{
  								if(index == 4)
  									{
  										scanCode = 0x0002;
  										keyType = MOUSE_KEY;
  									}
  								else
  									{
  										scanCode = 0x0001;
  										keyType = MOUSE_KEY;
  									}
  							}
                else
                {
                  scanCode = keyboard_ScanTable[index].scanCode;
                  keyType = keyboard_ScanTable[index].keyType;               
                }
            }
            keyQueue[i].keyState = KEY_STATE_UP;

            if(keyType == MULT_KEY)
            {
                isUpKeyDetected |= MULTIMEDA_REPORT;
            }
            else if(keyType  == PWR_KEY)
            {
                isUpKeyDetected |= POWER_REPORT;
            }
            else if(keyType == MOUSE_KEY)
            {
                isUpKeyDetected |= MOUSE_REPORT;
                prevClickStatus &= ~scanCode;
            }
            else if(keyType  == OTHER_KEY)
            {
                if(keyboard_ScanTable[index].scanCode == keyboard_Other_ScanTable[0])
                {
                    isPairButtonPressed = false;
                    isPairButtonDown = false;
                    Keyboard_Remove_Queue(i);
                    Debug_Print(DEBUG_MESSAGE_LEVEL_3, "pair Button released\r\n"); 
                }
            }
            else if(keyType & STD_KEY)
            {
                isUpKeyDetected |= KEYBOARD_REPORT;
            }
            else
            {
                /* Nothing */
            }
            break;
        }
    }
}

/*****************************************************************************
* Function Name: Keyboard_Count_Active_Keys()
******************************************************************************
* Summary:
* Counts the number of active column
*
* Parameters:
* uint8 colValue - column value
*
* Return:
* number of keys present
*
* Theory:
* Calculate the number of keys pressed and return the same.
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static uint8 Keyboard_Count_Active_Keys(uint8 colValue)
{
    uint8 noKeys=0;
    while(colValue)
    {
        /*Checks current column value for pressed or unpressed status*/
        if(colValue & 1)
        {
            noKeys++;
        }
        colValue = colValue>>BIT_1_POSITION;
    }
    return noKeys;
}

/*****************************************************************************
* Function Name: Keyboard_Detect_Ghost()
******************************************************************************
* Summary:
* Detect the ghost. Condition for the Ghost is shown below
*
*               | | | |
*              -o-0- - -
*               | | | |
*              -o-o- - -
*               | | | |
*               
*               o indicates the key pressed and 0 is the ghost detected when 3 keys 
*               are pressed
*
* Parameters:
* Row number
*
* Return:
* bool - True if ghost is detected
*
* Theory:
* When 3 buttons are pressed at a time, 4th button also shows as pressed. Based on 
* 3 buttons pressed can get which is that ghost button.
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static bool Keyboard_Detect_Ghost(uint8 row_no)
{
    uint8 i;
    uint8 noKeys = 0;
#if (NO_COLUMN_PORTS > 1)
    uint8 j;
    for(j=0;j<NO_COLUMN_PORTS;j++)
    {
        noKeys += Keyboard_Count_Active_Keys(curColumnStatus[row_no][j]);
    }
#else
    /*Get number of keys pressed*/
    noKeys += Keyboard_Count_Active_Keys(curColumnStatus[row_no]);
#endif /* (NO_COLUMN_PORTS > 1) */
    /*If number of keys pressed is less than 2 then There is no chance of 
    ghost key existence*/
    if(noKeys<2)
    {
        return false;
    }
    /*To get ghost key which is not pressed but showing status as pressed, check row by column
    status of the key. Check summary for how this is done*/
    for(i=0;i<ROWS;i++)
    {
        if(row_no != i)
        {
            noKeys =0;
#if (NO_COLUMN_PORTS > 1)
            for(j=0;j<NO_COLUMN_PORTS;j++)
            {
                noKeys += Keyboard_Count_Active_Keys((curColumnStatus[i][j] & curColumnStatus[row_no][j]));
            }
#else
        noKeys += Keyboard_Count_Active_Keys((curColumnStatus[i] & curColumnStatus[row_no]));
#endif /* (NO_COLUMN_PORTS > 1) */
            if(noKeys>1)
            {
                return true;
            }
        }
    }
    return false;
}

/*****************************************************************************
* Function Name: Keyboard_Detect_Keys()
******************************************************************************
* Summary:
* Identify the keys that has been pressed 
*
* Parameters:
* None
*
* Return
* None
*
* Theory:
* Based on the button row by column number will get which key is pressed in the 
* keyboard.
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Detect_Keys(void)
{
    uint8 i, j, index, col, p_col;
    /*By checking row by column key status detect which key is pressed or released*/
    for(i=0;i<ROWS;i++)
    {
        /*Check for any Ghost key detected*/
        if(!Keyboard_Detect_Ghost(i))
        {
            for(j=0;j<NO_COLUMN_PORTS;j++)
            {
                index = i+j*8*ROWS;

#if (NO_COLUMN_PORTS > 1)
                col = (curColumnStatus[i][j] ^ prevColumnStatus[i][j]);
                p_col = (col & prevColumnStatus[i][j]);
                col = (col & curColumnStatus[i][j]);
#else
                col = (curColumnStatus[i] ^ prevColumnStatus[i]);
                p_col = (col & prevColumnStatus[i]);
                col = (col & curColumnStatus[i]);                
#endif /* (NO_COLUMN_PORTS > 1) */
                while((col != 0) || (p_col != 0))
                {
                    /*If column value is 1 then update Keyboard queue with index*/
                    if(col & BIT_0_MASK)
                    {
                        Keyboard_Add_Queue(index);
                    }
                    /*If previous column value is 1 then update un-pressed status for status change 
                    in column*/
                    if(p_col & BIT_0_MASK)
                    {
                        Keyboard_Update_Release_Key_State(index);
                    }
                    index+=ROWS;
                    col = col>>BIT_1_POSITION;
                    p_col = p_col>>BIT_1_POSITION;
                }
#if (NO_COLUMN_PORTS > 1)
                prevColumnStatus[i][j] = curColumnStatus[i][j];
#else 
                prevColumnStatus[i] = curColumnStatus[i];
#endif /* (NO_COLUMN_PORTS > 1) */
            }
        }
    }
}

/*****************************************************************************
* Function Name: Keyboard_Scan()
******************************************************************************
* Summary:
* Scan keyboard for the any key is pressed
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Scan keyboard key pressed by getting column status and update the key state
* after release.
*
* Side Effects:
* prevColumnStatus is updated
* 
* Note:
* None
*****************************************************************************/
static void Keyboard_Scan(void)
{
    uint8 col, i;
#if (NO_COLUMN_PORTS > 1)
    uint8 columnPorts;
    uint8 columnState[NO_COLUMN_PORTS];
#endif /* (NO_COLUMN_PORTS > 1) */
    
    Keyboard_Rows_Write(~((uint8)Keyboard_Rows_MASK>>Keyboard_Rows_SHIFT));
    
#if (NO_COLUMN_PORTS > 1)
    Keyboard_Columns_1_Write(Keyboard_Columns_1_MASK>>Keyboard_Columns_1_SHIFT);
    Keyboard_Columns_2_Write(Keyboard_Columns_2_MASK>>Keyboard_Columns_2_SHIFT);
    Keyboard_Columns_3_Write(Keyboard_Columns_3_MASK>>Keyboard_Columns_3_SHIFT);
#else
    Keyboard_Columns_Write(Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT);
#endif /* (NO_COLUMN_PORTS > 1) */

    KeyboardDelay();
#if (NO_COLUMN_PORTS > 1)
    /* Update this part of the code if more ports are getting used */
    columnState[0] = (~(uint8)Keyboard_Columns_1_Read() & Keyboard_Columns_1_MASK);
    columnState[1] = (~(uint8)Keyboard_Columns_2_Read() & Keyboard_Columns_2_MASK);
    columnState[2] = (~(uint8)Keyboard_Columns_3_Read() & Keyboard_Columns_3_MASK);
    
    col = (columnState[0] | columnState[1] | columnState[2]);
#else
    /*Read column value*/
    col = (~(uint8)Keyboard_Columns_Read() & (Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT));
#endif /* (NO_COLUMN_PORTS > 1) */
    /*If column value is there then scan for column to get the key press activity*/
    if(col)
    {
        Keyboard_Scan_Column();
    }
    else
    {
        /*If no column value is present check for previous column value and check which
        key is unpressed*/
        if(prevCol)
        {
            for(i=0;i<ROWS;i++)
            {
#if (NO_COLUMN_PORTS > 1)
                for(columnPorts = 0; columnPorts < NO_COLUMN_PORTS; columnports++)
                {
                    prevColumnStatus[i][columnPorts] = 0;
                }
#else
                prevColumnStatus[i] = 0;
#endif /* (NO_COLUMN_PORTS > 1) */ 
            }
            
            for(i=0;i<KEY_QUEUE_LEN;i++)
            {
                if(keyQueue[i].index != INVALID_INDEX)
                {
                    Keyboard_Update_Release_Key_State(keyQueue[i].index);
                }
            }
        }
    }
    prevCol = col;
}


#ifdef BACK_CHANNEL_SUPPORT
/*****************************************************************************
* Function Name: Keyboard_Update_BackChannel_Data()
******************************************************************************
* Summary:
* Updates the status of the led for caps lock, num lock and scroll lock
*
* Parameters:
* back channel data
*
* Return:
* None
*
* Theory:
* Update the status led depending upon the back channel data
*
* Side Effects:
* back_channel_data and prevScanCode is updated 
* 
* Note:
* None
*****************************************************************************/
void Keyboard_Update_BackChannel_Data(uint8 back_channel_data)
{
    /* This is according to the HID specification */
    switch(prevScanCode)
    {
#if (KEY_CAP_LOCK != NOKEY)
        case KEY_CAP_LOCK:
            back_channel_data = (back_channel_data ^ BIT_1_MASK);
            break;
#endif /* (KEY_CAP_LOCK != NOKEY) */
#if (KEY_NUM_LOCK != NOKEY)
        case KEY_NUM_LOCK: 
            back_channel_data = (back_channel_data ^ BIT_0_MASK);
            break;
#endif /* (KEY_NUM_LOCK != NOKEY) */
#if (KEY_SCROLL_LOCK != NOKEY)
        case KEY_SCROLL_LOCK:
            back_channel_data = (back_channel_data ^ BIT_2_MASK);
            break;
#endif /* (KEY_SCROLL_LOCK != NOKEY) */
        default:
            break;
    }
#if (KEY_CAP_LOCK != NOKEY)
    if(back_channel_data & BIT_1_MASK)
    {
        CAPS_LOCK_LED_ON;
    }
    else 
    {
        CAPS_LOCK_LED_OFF;
    }
#endif /* (KEY_CAP_LOCK != NOKEY) */
#if (KEY_NUM_LOCK != NOKEY)
    if(back_channel_data & BIT_0_MASK)
    {
        NUM_LOCK_LED_ON;
    }
    else 
    {
        NUM_LOCK_LED_OFF;
    }
#endif /* (KEY_NUM_LOCK != NOKEY) */
#if (KEY_SCROLL_LOCK != NOKEY)
    if(back_channel_data & BIT_2_MASK)
    {
        SCROLL_LOCK_LED_ON;
    }
    else 
    {
        SCROLL_LOCK_LED_OFF;
    }
#endif /* (KEY_SCROLL_LOCK != NOKEY) */
}
#endif /* Keyboard_Update_BackChannel_Data */

/*****************************************************************************
* Function Name: Keyboard_Poll()
******************************************************************************
* Summary:
* Keyboard module will be polled for any activity
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Scans the keyboard matrix and also updates the queue for the debounce
*
* Side Effects:
* sendKeyboardReport and lastTransferTimeStamp is updated
* 
* Note:
* None
*****************************************************************************/
void Keyboard_Poll(void)
{   
    Keyboard_Scan();
    /*If any key state is updated in Queue post Keyboard event*/
    if(Keyboard_Update_Queue())
    {            
        DEVICE_POST_EVENT(KEYBOARD_EVENT);
        sendKeyboardReport = true;
    }
    else if(sendKeepAlivePacket)
    {
        Debug_Print(DEBUG_MESSAGE_LEVEL_3,"sendKeepAlivePacket",Timer_Get_Time_Stamp() - lastTransferTimeStamp);
        if(Timer_Time_Elapsed(lastTransferTimeStamp,KEYBOARD_KEEP_ALIVE_TIMEOUT))
        {
            DEVICE_POST_EVENT(KEYBOARD_EVENT);
        }
    }
}

/*****************************************************************************
* Function Name: Keyboard_Get_Report()
******************************************************************************
* Summary:
* Keyboard module provides the Report data for transmitting
*
* Parameters:
* report - Remport structure pointer.
*
* Return:
* ReportType - Typre of report.
*
* Theory:
* Collects the data from the keyQueue and updates the report structure
*
* Side Effects:
* keyQueue is updated
* 
* Note:
* None
*****************************************************************************/
ReportType Keyboard_Get_Report(Report *report)
{
    static Keyboard_Report   prevKeyboardReport;      /* structure for sending keyboard report */
    static Power_Report      prevPowerReport;         /* structure for sending power report */
    static Multimedia_Report prevMultimediaReport;    /* structure for sending multimedia report */

    uint8 i,index;
    ReportType reportType=NO_REPORT;
    KeyType keyType;
    uint8 scanCode;
    
    report->mouse_report.click |= prevClickStatus;
    /*Check for keyboard event*/
    if(!DEVICE_GET_EVENT(KEYBOARD_EVENT))
    {
        return NO_REPORT;
    }
    /*Update report structure values using Keyboard queue to send keyboard report*/
    if(sendKeyboardReport)
    {
#ifdef BACK_CHANNEL_SUPPORT
        prevScanCode = NOKEY;
#endif /* BACK_CHANNEL_SUPPORT */
        sendKeyboardReport = false;        
        reportType |= isUpKeyDetected;
        isUpKeyDetected = NO_REPORT;
        for (i = 0; i < KEY_QUEUE_LEN; i++)
        {
            index = keyQueue[i].index;
            if((index != INVALID_INDEX) && (keyQueue[i].debounceValue == 0))
            {
  						if(MotionSensorState && (index == 4 || index == 6))
  							{
  								if(index == 4)
  									{
  										scanCode = 0x0002;
  										keyType = MOUSE_KEY;
  									}
  								else
  									{
  										scanCode = 0x0001;
  										keyType = MOUSE_KEY;

  									}
  							}
                else
                {
                  scanCode = keyboard_ScanTable[index].scanCode;
                  keyType = keyboard_ScanTable[index].keyType;               
                }
                Debug_Print(DEBUG_MESSAGE_LEVEL_3,"index = %d\r\n",index);
                
#ifdef ENABLE_IR_CODES /*If BLE is not enabled IR will be enabled to send keyboard commands*/
                report->ir_report.command = keyboard_Ir_ScanTable[index];
#endif /* ENABLE_IR_CODES */

                if((keyType == MULT_KEY) && (keyQueue[i].isDataSent ==0))
                {
                    reportType |= MULTIMEDA_REPORT;
                    keyQueue[i].isDataSent = 1;
                    report->multimedia_report.multimedia_key_code = multimedia_Keyboard_ScanTable[scanCode];
                }
                else if((keyType == PWR_KEY) && (keyQueue[i].isDataSent ==0))
                {
                    reportType |= POWER_REPORT;
                    keyQueue[i].isDataSent = 1;
                    report->power_report.power_key_code = scanCode;
                }
                else if((keyType == MOUSE_KEY) && (keyQueue[i].isDataSent ==0))
                {
                    reportType |= MOUSE_REPORT;
                    keyQueue[i].isDataSent = 1;
                    report->mouse_report.click |= scanCode;
                    prevClickStatus |= scanCode;
                }
                else if(keyType == OTHER_KEY)
                {
                    if(scanCode == keyboard_Other_ScanTable[0])
                    {
                        isPairButtonPressed  = true;
                        keyQueue[i].isDataSent = 1;
                        Debug_Print(DEBUG_MESSAGE_LEVEL_3, "pair Button Pressed\r\n");
                    }
                }
                else if(keyType & STD_KEY)
                {
                    if((scanCode ==  KEY_CAP_LOCK) || (scanCode == KEY_NUM_LOCK) \
                                                        || (scanCode == KEY_SCROLL_LOCK))
                    {
#ifdef BACK_CHANNEL_SUPPORT
                        prevScanCode = scanCode;
                        backChannelRequest = 1;
#endif /* BACK_CHANNEL_SUPPORT */
                    }

                    if(keyType & MODIFIER_KEY)
                    {
                        reportType |= KEYBOARD_REPORT;
                        keyQueue[i].isDataSent = 1;
                        report->keyboard_report.mkey |= scanCode;
                    }
                    else
                    {
                        if(keyQueue[i].isDataSent == 0)
                        {
                            reportType |= KEYBOARD_REPORT;
                            keyQueue[i].isDataSent = 1;
                            report->keyboard_report.keycode[report->keyboard_report.keylength_used++] = scanCode;
                        }
                    }
                }
                Keyboard_Remove_Queue(i);
            }
        }
        prevReportType = reportType;
        if(reportType != NO_REPORT)
        {
            lastTransferTimeStamp = Timer_Get_Time_Stamp();
            prevReportType = reportType;
            Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Send the Keyboard report\r\n");
#ifdef ENABLE_IR_CODES/*If BLE is not enabled IR will be enabled to send keyboard commands*/
            report->ir_report.isRepeatCode  = REPEATCODE_DISABLE;
#endif /* ENABLE_IR_CODES */ 
            if(reportType & KEYBOARD_REPORT)
            {   
                memcpy(&prevKeyboardReport.mkey, &report->keyboard_report.mkey, KEYBOARD_REPORT_SIZE);
            }
            if(reportType & POWER_REPORT)
            {
                prevPowerReport.power_key_code =  report->power_report.power_key_code;
            }
            if(reportType & MULTIMEDA_REPORT)
            {
                prevMultimediaReport.multimedia_key_code = report->multimedia_report.multimedia_key_code;
            }
        }
    }
    else if(sendKeepAlivePacket)
    {
#ifdef ENABLE_IR_CODES
        /*If BLE is not enabled IR will be enabled to send keyboard commands*/
        if((prevReportType != NO_REPORT) && !(prevReportType & MOUSE_REPORT))
        {
            report->ir_report.isRepeatCode = REPEATCODE_ENABLE;
        }
#endif /* ENABLE_IR_CODES */
        lastTransferTimeStamp = Timer_Get_Time_Stamp();
        if(prevReportType & KEYBOARD_REPORT)
        {
            Debug_Print(DEBUG_MESSAGE_LEVEL_3,"Send the report ALIVE PACKET\r\n");
            memcpy(&report->keyboard_report.mkey, &prevKeyboardReport.mkey,KEYBOARD_REPORT_SIZE);
            reportType |= KEYBOARD_REPORT;
        }
        if(prevReportType & POWER_REPORT)
        {
            report->power_report.power_key_code = prevPowerReport.power_key_code;
            reportType |= POWER_REPORT;
        }
        if(prevReportType & MULTIMEDA_REPORT)
        {
            report->multimedia_report.multimedia_key_code = prevMultimediaReport.multimedia_key_code;
            reportType |= MULTIMEDA_REPORT;
        }
    }
    else
    {
        prevReportType = NO_REPORT;
    }
    Debug_Print(DEBUG_MESSAGE_LEVEL_3, "Report Type = %d",reportType);
    return reportType;
}

/*****************************************************************************
* Function Name: Keyboard_Set_State()
******************************************************************************
* Summary:
* This functions is used to set the device state and make corresponding configuration
* changes in keyboard module
*
* Parameters:
* state - state of the device
*
* Return:
* None
*
* Theory:
* Enable\Disable the interrupt for the keyboard matrix 
*
* Side Effects:
* None
* 
* Note:
* Note
*****************************************************************************/
void Keyboard_Set_State(Device_State state)
{
    /*If device state is inactive enable the interrupt ti get device activity*/
    if(state != DEVICE_ACTIVE)
    {
        Keyboard_Columns_ClearInterrupt();
#if (NO_COLUMN_PORTS > 1)
        Keyboard_Columns_1_Write(Keyboard_Columns_1_MASK>>Keyboard_Columns_1_SHIFT);
        Keyboard_Columns_2_Write(Keyboard_Columns_2_MASK>>Keyboard_Columns_2_SHIFT);
        Keyboard_Columns_3_Write(Keyboard_Columns_3_MASK>>Keyboard_Columns_3_SHIFT);
#else
        Keyboard_Columns_Write(Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT);        
#endif /* (NO_COLUMN_PORTS > 1) */
        Keyboard_Columns_Interrupt_Enable();
    }
    else
    {
        /*If device state is active disable the interrupt*/
        Keyboard_Columns_Interrupt_Disable();
    }
}

/*****************************************************************************
* Function Name: Keyboard_IsActive()
******************************************************************************
* Summary:
* Checks any key is pressed in keyboard matrix
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* checks any key is pressed in keyboard matrix by checking the prevCol variable
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
bool Keyboard_IsActive(void)
{
    return (prevCol != 0);
}

/*****************************************************************************
* Function Name: Keyboard_Stop()
******************************************************************************
* Summary:
* Function is used to stop keyboard module.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Stops the keyboard module by disabling the interrupt and changing the drive 
* modes to High Impedance Digital
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Keyboard_Stop(void)
{
    Keyboard_Columns_Interrupt_Disable();
    Keyboard_Columns_SetDriveMode(Keyboard_Columns_DM_DIG_HIZ);
    Keyboard_Rows_SetDriveMode(Keyboard_Rows_DM_DIG_HIZ);
}

#endif /* DISABLE_KEYBOARD */
